package org.ricks.ioc.cfg;

import org.ricks.ioc.utils.BooleanUtils;
import org.ricks.ioc.utils.Logger;
import org.ricks.ioc.utils.StringUtils;

import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 属性文件加载器.
 */
public class RicksPropertiesLoader {
    private static final String RICKS_PREFIX = "ricks";
    private static final String APPLICATION_PREFIX = "application";
    private static final String PROPERTIES_SUFFIX = ".properties";

    private static final ClassLoader loader = RicksPropertiesLoader.class.getClassLoader();
    /**
     * 所有配置
     */
    private static final Map<String, String> properties = new ConcurrentHashMap<>(128);

    /**
     * 加载启动命令行的参数.
     * <p>命令行参数优先级 大于 配置文件优先级</p>
     * Noark在启动时命令行参数需要使用双杠--指定，参数即为配置文件中的参数配置相同！
     *
     * @param args 启动命令行的参数
     */
    public void loadingArgs(String... args) {
        Arrays.asList(args).forEach(this::loadArg);
    }

    private void loadArg(String arg) {
        if (!arg.startsWith("--")) return;
        int index = arg.indexOf('=', 2);
        if (index <= 1) return;
        String optionName = arg.substring(2, index);
        String optionValue = arg.substring(index + 1);
        if (StringUtils.isBlank(optionName) || StringUtils.isBlank(optionValue)) {
            throw new IllegalArgumentException("Invalid argument syntax: " + arg);
        }
        properties.put(optionName, optionValue);
    }


    /**
     * 加载系统配置文件中的内容.
     * <p>
     * application-test.properties中的内容会覆盖application.properties中的配置
     */
    public static Map<String, String> loadingProperties() {

        String filePath = System.getProperty("config.file");
        if(!StringUtils.isBlank(filePath)){
            properties.putAll(loadingFileByPath(filePath));
        }else {
            // --ricks.profiles.env=dev/prod/test     # 指定运行环境
            String profile = properties.getOrDefault("ricks.profiles.env", "");

            // 优先载入bootstrap.properties
            properties.putAll(loadingFile(RICKS_PREFIX, profile));

            // 然后再载入application.properties
            properties.putAll(loadingFile(APPLICATION_PREFIX, profile));
        }
        return properties;
    }

    private static HashMap<String, String> loadingFile(String filename, String profile) {
        HashMap<String, String> config = new HashMap<>(128);
        loadingFile(filename + PROPERTIES_SUFFIX, config);

        // 加载指定的Profile
        if (!StringUtils.isBlank(profile)) {
            loadingFile(filename + "-" + profile + PROPERTIES_SUFFIX, config);
        }
        return config;
    }

    private static void loadingFile(String filename, Map<String, String> config) {
        Logger.debug(" start action load properties  -- filename:"+ filename);
        try (InputStream in = loader.getResourceAsStream(filename)) {
            if (in == null) {
                return;
            }
            Logger.debug(" starting load properties   filename:"+ filename);
            Properties props = new Properties();
            InputStreamReader isr = new InputStreamReader(in);
            props.load(isr);

            for (Entry<Object, Object> e : props.entrySet()) {
                String key = e.getKey().toString().trim();
                // 有更高优化级的配置，忽略这个配置
                if (properties.containsKey(key)) {
                    continue;
                }

                // 收录这个新的配置
                String value = e.getValue().toString().trim();
                if (config.put(key, value) != null) {
                    System.err.println("覆盖配置 >>" + key + "=" + value);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("配置文件格式异常... filename=" + filename);
        }
    }

    private static HashMap<String, String> loadingFileByPath(String filePath) {
        HashMap<String, String> config = new HashMap<>(128);
        try {
            File file =new File(filePath);
            Properties props = new Properties();
            FileInputStream isr = new FileInputStream(file);
            props.load(isr);

            for (Entry<Object, Object> e : props.entrySet()) {
                String key = e.getKey().toString().trim();
                // 有更高优化级的配置，忽略这个配置
                if (properties.containsKey(key)) {
                    continue;
                }

                // 收录这个新的配置
                String value = e.getValue().toString().trim();
                if (config.put(key, value) != null) {
                    System.err.println("覆盖配置 >>" + key + "=" + value);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("配置文件格式异常... filePath=" + filePath);
        }
        return config;
    }

    public static Map<String, String> getProperties() {
        return properties;
    }

    public static boolean toBool(String key) {
        return BooleanUtils.toBoolean(properties.getOrDefault(key,"false"));
    }

    public static int toInt(String key) {
        String value = properties.getOrDefault(key,"0");
        return Integer.parseInt(value);
    }

    public static short toShort(String key) {
        String value = properties.getOrDefault(key,"0");
        return Short.parseShort(value);
    }

    public static int toIntOrDefault(String key,int defaultValue) {
        String value = properties.get(key);
        return StringUtils.isBlank(value) ? defaultValue : Integer.parseInt(value);
    }

    public static String get(String key) {
        return properties.getOrDefault(key,"");
    }

    public static String getOrDefault(String key,String defaultValue) {
        return properties.getOrDefault(key,defaultValue);
    }

    public static void main(String[] args) {
        RicksPropertiesLoader loadr = new RicksPropertiesLoader();
        loadingProperties();
        getProperties().forEach((k,v) -> System.err.println(k +" and "+ v));

    }
}